package com.wang.socket;


import com.wang.conf.AppData;
import com.wang.packpojo.ConMsg;
import com.wang.pojo.Device;
import com.wang.util.DevControlUtil;
import com.wang.util.GetByteEncodeUtil;
import com.wang.util.ModBusUtil;
import com.wang.util.PrintUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义解码器
 *
 * @author wcy   添加功能解析功能
 */
public class CustomDecoder15 extends ByteToMessageDecoder {

    private final int BASE_LENGTH = 1;

    private String heart = "METER";
    private String reg = "DSDEVREG";
    Integer jNum = 0;  //垃圾数据次数
    Integer m1Num = 0;  //垃圾数据次数
    Integer m2Num = 0;  //垃圾数据次数
    Integer m3Num = 0;  //垃圾数据次数
    Integer mCountNum = 0;  //控制垃圾数据次数

    /**
     * 十六进制字符串数组解析
     *
     * @param ctx
     * @param in   传入数据
     * @param list 添加解码消息
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) {


        Logger logger = LoggerFactory.getLogger(PrintUtil.class);

        int beginIndex;//记录包开始位置

        while (true) {
            //获取包头开始的index
            beginIndex = in.readerIndex();
            // 将当前的readerIndex备份到markedReaderIndex中
            in.markReaderIndex();
            //获取字节可读取长度
            int reablesLength = in.readableBytes();
            //判断是不是心跳包
            if(reablesLength >= heart.getBytes().length){

                //1、心跳包处理 读取前5位字节 判断是不是心跳包数据
                byte[] bytes1 = new byte[heart.getBytes().length];
                in.readBytes(bytes1);

                String encoding1 = GetByteEncodeUtil.getEncoding(bytes1);
                String data1 = null;
                try {
                    data1 = new String(bytes1, encoding1);
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
                if (data1.equals(heart)) {
                    list.add(data1);
                    //回收已读字节
                    in.discardReadBytes();
                    return;
                }else if(reablesLength >= reg.getBytes().length){

                    in.readerIndex(beginIndex);
                    //2、注册包处理 读取前8个字节  判断是不是注册包
                    byte[] bytes2 = new byte[reg.getBytes().length];
                    in.readBytes(bytes2);

                    String encoding2 = GetByteEncodeUtil.getEncoding(bytes2);
                    String data2 = null;
                    try {
                        data2 = new String(bytes2, encoding2);
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    if(data2.equals(reg)){
                        int j = reg.length();
                        //读取整个数据
                        in.readerIndex(beginIndex);
                        byte[] bytes3 = new byte[reablesLength];
                        in.readBytes(bytes3);
                        //将数据转换成16进制字符串
                        String data3 = new String(bytes3);
                        for(int i = reg.length();i<data3.length();i++){
                            char s = data3.charAt(i);

                            if(String.valueOf(s).equals(";")){
                                j = i;
                                break;
                            }
                        }
                        String dsdevReg = data3.substring(0,j+1);
                        //判断是不是注册包
                        //重置读取点
                        in.readerIndex(beginIndex);
                        byte[] byte4 = new byte[dsdevReg.getBytes().length];
                        in.readBytes(byte4);
                        //将数据转换成16进制字符串
                        String encoding7 = GetByteEncodeUtil.getEncoding(byte4);
                        String finalData2 = null;
                        try {
                            finalData2 = new String(byte4, encoding7);
                            list.add(finalData2.replaceAll(";",""));
                            //回收已读字节
                            in.discardReadBytes();
                            return;
                        } catch (UnsupportedEncodingException e) {
                            PrintUtil.print("读取数据异常");
                            in.clear();
                            e.printStackTrace();
                        }



                    }else {
                        //3、数据处理

                        //重置读取点
                        in.readerIndex(beginIndex);
                        dataHander(ctx,in,list,beginIndex);
                        return;
                    }
                }else {
                    //重置读取点
                    in.readerIndex(beginIndex);
                    dataHander(ctx,in,list,beginIndex);
                    return;
                }
            }else {
                in.clear();
                return;
            }
        }

    }

    //数据处理
    public void dataHander(ChannelHandlerContext ctx, ByteBuf in, List<Object> list,int beginIndex){
        String address = getRemoteAddress(ctx);
        //获取字节可读取长度
        int reablesLength = in.readableBytes();

        String isContain = "false";
        if (SocketMap.mRegPassDeviceMap.containsKey(address)) {
            isContain = "mContain";

            byte[] bytes = new byte[reablesLength];
            in.readBytes(bytes);

            try {
                ConMsg conMsg = SocketMap.mRegPassDeviceMap.get(address);
                String data = ModBusUtil.bytes2HexString(bytes);
                PrintUtil.print(conMsg.getDevice().getDevGId()+"MODBUS打印调试数据："+data);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //重置读取点
            in.readerIndex(beginIndex);

        }
        if (SocketMap.jRegPassDeviceMap.containsKey(address)) {

            byte[] bytes = new byte[reablesLength];
            in.readBytes(bytes);

            String encoding4 = GetByteEncodeUtil.getEncoding(bytes);
            String data = null;
            try {

                ConMsg conMsg = SocketMap.jRegPassDeviceMap.get(address);
                data = new String(bytes, encoding4);
                System.out.println(conMsg.getDevice().getDevGId()+"JSON打印调试数据："+data);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            //重置读取点
            in.readerIndex(beginIndex);
            isContain = "jContain";
        }
        if (SocketMap.c2RegPassDeviceMap.containsKey(address)) {
            isContain = "c2Contain";

            byte[] bytes = new byte[reablesLength];
            in.readBytes(bytes);

            try {
                ConMsg conMsg = SocketMap.c2RegPassDeviceMap.get(address);
                String data = ModBusUtil.bytes2HexString(bytes);
                System.out.println(conMsg.getDevice().getDevGId()+"CustomTWO打印调试数据："+data);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //重置读取点
            in.readerIndex(beginIndex);

        }
        if (isContain.equals("false")) {
            in.clear();
           PrintUtil.print(address+"设备未注册，收到了数据");
            return;
        }

        //3、判断是不是json数据
        //--------------------------------
        if (isContain.equals("jContain")) {

            //方式  读取左大括号 +1   读取到右括号-1
            //先读取第一个字节 是否是 { 如果是依次读字节
            byte[] byteleft = new byte[1];
            in.readBytes(byteleft);

            String encoding6 = GetByteEncodeUtil.getEncoding(byteleft);
            String firstData = null;
            try {
                firstData = new String(byteleft, encoding6);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            if (firstData.equals("{")) {
                //下标
                int indexFlag = 0;
                int intFlag = 0;


                indexFlag++;
                intFlag++;
                //依次往下读
                //读取一个字节 -1 代表已经读过一个字节
                for (int i = 0; i < reablesLength - 1; i++) {

                    byte[] bytesFlag = new byte[1];
                    in.readBytes(bytesFlag);
                    indexFlag++;
                    String encoding7 = GetByteEncodeUtil.getEncoding(bytesFlag);
                    String flag = null;
                    try {
                        flag = new String(bytesFlag, encoding7);
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    if (flag.equals("{")) {
                        //标识+1
                        intFlag++;
                    }
                    if (flag.equals("}")) {
                        //标识-1
                        intFlag--;
                    }
                    if (intFlag == 0) {
                        //如果标识为0 查询到所有json数据
                        break;
                    }
                }

                if (intFlag == 0) {


                    //截取数据
                    //重置字节读取下标
                    in.resetReaderIndex();
                    byte[] jsonBytes = new byte[indexFlag];
                    in.readBytes(jsonBytes);
                    String encoding8 = GetByteEncodeUtil.getEncoding(jsonBytes);

                    String jsonData = null;
                    try {
                        jsonData = new String(jsonBytes, encoding8);
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }

                    //添加数据
                    list.add(jsonData);
                    //回收已读字节
                    in.discardReadBytes();
                    jNum = 0;

                    return;

                } else {

                    //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                    //如果垃圾数据次数不超过5次 重置
                   /* if(jNum<=10) {
                        in.readerIndex(beginIndex);
                        jNum++;
                    }else {
                        //如果垃圾数据次数超过5次  清空数据
                        in.clear();
                        jNum =0;
                    }*/
                    in.readerIndex(beginIndex);
                    return;
                }


            }else {
                //清空字节
                in.clear();
                //回收已读字节
                //in.discardReadBytes();
                return;
                //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                   /* in.readerIndex(beginIndex);
                    return;*/
            }
        }
        //4、判断是不是modbus数据
       else if (isContain.equals("mContain")) {
            //最后一步 modbus数据读取


            if (reablesLength >= 5){

                //判断设备
                ConMsg conMsg =  SocketMap.mRegPassDeviceMap.get(address);
                Device device = conMsg.getDevice();

                //截取功能码 判断是不是03 读取数据
                byte[] funMdatas = new byte[2];
                in.readBytes(funMdatas);
                String funCode = bytes2HexString(funMdatas).split(" ")[1];

                //logger.info("地址位"+addressCode+"功能码"+funCode);

                if (funCode.equals("03") || funCode.equals("04")) {  //如果是读取数据03  04也按读取数据处理

                    //重置读取位
                    in.resetReaderIndex();

                    //modbus数据读取前3个字节 获取数据长度
                    byte[] mdatas = new byte[3];
                    in.readBytes(mdatas);
                    //截取数据位长度
                    String mlength = bytes2HexString(mdatas).split(" ")[2];


                    //重置读取位
                    in.resetReaderIndex();

                    Integer length = hex2decimal(mlength);

                    int totalDataLength = 3 + length + 2;  //地址 +功能 +数据长度  3   加上数据长度 +  校验位长度2


                    //如果可读数据位长度小于  数据位长度  返回 等待下一次数据到期在读
                    if (reablesLength < totalDataLength) {
                        //in.readerIndex(beginIndex);
                        //清空数据 重新读取
                           /* in.clear();
                            return;*/
                        if(m1Num<=5) {

                            System.out.println("打印调试数据modbus1："+m1Num);
                            in.readerIndex(beginIndex);
                            m1Num++;
                        }else {
                            //如果垃圾数据次数超过5次  清空数据
                            in.clear();
                            m1Num =0;
                        }
                        return;
                    }
                    byte[] mdatas2 = new byte[totalDataLength];

                    in.readBytes(mdatas2);


                    //计算modbus数据合法性
                    //先将bytes 转换成16进制字符串
                    String baseData = ModBusUtil.bytes2HexString(mdatas2);


                    String baseDataStr = baseData.replaceAll(" ", "");
                    String[] baseDatas = baseData.split(" ");

                    //要校验的数据
                    String[] checkDatas = Arrays.copyOfRange(baseDatas, 0, baseDatas.length - 2);
                    StringBuffer sb1 = new StringBuffer();
                    for (String s : checkDatas) {
                        sb1.append(s);
                    }

                    byte[] checkBytes = ModBusUtil.HexString2Bytes(sb1.toString());


                    //计算crc值
                    String checkCrc2 = ModBusUtil.getCRC3(checkBytes);
                    //截取原有crc值
                    String checkCrc1 = baseDataStr.substring(baseDataStr.length() - 4);

                    if (checkCrc1.equals(checkCrc2)) {
                        //添加数据
                        list.add(baseData);

                        //回收已读字节
                        in.discardReadBytes();
                        m2Num = 0;
                        return;

                    } else {
                           /* //回收已读字节
                            in.discardReadBytes();
                            return;*/

                        //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                        //如果垃圾数据次数不超过5次 重置
                        if(m2Num<=3) {

                            System.out.println("打印调试数据modbus2："+m2Num);
                            in.readerIndex(beginIndex);
                            m2Num++;
                        }else {
                            //如果垃圾数据次数超过5次  清空数据
                            in.clear();
                            m2Num =0;
                        }
                        return;
                    }
                } else {
                    //判断设备处理 指令处理

                    if(AppData.returnMap.containsKey(device.getDevGId())){


                        if(device.getDevGId().equals("GJ004_V7YK7LDPE")){

                            //付红航定制控制阀门
                            DevControlUtil.handlerControl3(in, device.getDevGId(), mCountNum);

                        }else {

                            //如果功能码是10 例外处理 目前先作为电极校准处理

                            if (funCode.equals("10")) {

                                DevControlUtil.handerControl2(in, device.getDevGId(), mCountNum);
                            } else {
                                //通用性 单独处理
                                DevControlUtil.handerControl1(in, device.getDevGId(), mCountNum);
                            }
                        }
                    }else{
                        //清空垃圾数据
                        in.clear();
                    }
                    return;

                }

            }else {
                in.clear();
               PrintUtil.print("清空缓冲区：字节数小于5，不符合数据");
                return;
            }

        } else if (isContain.equals("c2Contain")) {  //自定义设备也是modbus 设备



            //最后一步 modbus数据读取
            if (reablesLength >= 5){

                //判断设备
                //ConMsg conMsg =  SocketMap.c2RegPassDeviceMap.get(address);
                //Device device = conMsg.getDevice();

                //截取功能码 判断是不是03 读取数据
                byte[] funMdatas = new byte[2];
                in.readBytes(funMdatas);
                String funCode = bytes2HexString(funMdatas).split(" ")[1];


                if (funCode.equals("03") ) {  //如果是读取数据03  06 10 写入数据

                    //重置读取位
                    in.resetReaderIndex();

                    //modbus数据读取前3个字节 获取数据长度
                    byte[] mdatas = new byte[3];
                    in.readBytes(mdatas);
                    //截取数据位长度
                    String mlength = bytes2HexString(mdatas).split(" ")[2];


                    //重置读取位
                    in.resetReaderIndex();

                    Integer length = hex2decimal(mlength);

                    int totalDataLength = 3 + length + 2;  //地址 +功能 +数据长度  3   加上数据长度 +  校验位长度2

                    //如果可读数据位长度小于  数据位长度  返回 等待下一次数据到期在读
                    if (reablesLength < totalDataLength) {
                        //in.readerIndex(beginIndex);
                        //清空数据 重新读取
                           /* in.clear();
                            return;*/
                        if(m1Num<=5) {

                            System.out.println("打印调试数据modbus1："+m1Num);
                            in.readerIndex(beginIndex);
                            m1Num++;
                        }else {
                            //如果垃圾数据次数超过5次  清空数据
                            in.clear();
                            m1Num =0;
                        }
                        return;
                    }
                    byte[] mdatas2 = new byte[totalDataLength];

                    in.readBytes(mdatas2);


                    //计算modbus数据合法性
                    //先将bytes 转换成16进制字符串
                    String baseData = ModBusUtil.bytes2HexString(mdatas2);


                    String baseDataStr = baseData.replaceAll(" ", "");
                    String[] baseDatas = baseData.split(" ");

                    //要校验的数据
                    String[] checkDatas = Arrays.copyOfRange(baseDatas, 0, baseDatas.length - 2);
                    StringBuffer sb1 = new StringBuffer();
                    for (String s : checkDatas) {
                        sb1.append(s);
                    }

                    byte[] checkBytes = ModBusUtil.HexString2Bytes(sb1.toString());


                    //计算crc值
                    String checkCrc2 = ModBusUtil.getCRC3(checkBytes);
                    //截取原有crc值
                    String checkCrc1 = baseDataStr.substring(baseDataStr.length() - 4);

                    if (checkCrc1.equals(checkCrc2)) {
                        //添加数据
                        list.add(baseData);

                        //回收已读字节
                        in.discardReadBytes();
                        m2Num = 0;
                        return;

                    } else {
                           /* //回收已读字节
                            in.discardReadBytes();
                            return;*/

                        //如果不包含 代表数据不全，返回读的指针 等待下一次的数据到期在读
                        //如果垃圾数据次数不超过5次 重置
                        if(m2Num<=3) {

                            System.out.println("打印调试数据modbus2："+m2Num);
                            in.readerIndex(beginIndex);
                            m2Num++;
                        }else {
                            //如果垃圾数据次数超过5次  清空数据
                            in.clear();
                            m2Num =0;
                        }
                        return;
                    }
                }else if(funCode.equals("06")){

                    //重置读取位
                    in.resetReaderIndex();




                    //直接去前6个字节  78 作为crc
                    if(reablesLength>=8) {
                        byte[] mdatas = new byte[8];
                        in.readBytes(mdatas);
                        String data = bytes2HexString(mdatas);


                        byte[] data1 = {mdatas[0],mdatas[1],mdatas[2],mdatas[3],mdatas[4],mdatas[5]};
                        byte[] crcbyte = {mdatas[6],mdatas[7]};
                        String checkCrc2 = ModBusUtil.getCRC3(data1);

                        String crc = ModBusUtil.bytes2HexString(crcbyte);
                        if(crc.replace(" ","").equals(checkCrc2)){
                            //添加数据
                            list.add(data);
                            //回收已读字节
                            in.discardReadBytes();
                            return;
                        }
                    }else {
                        in.clear();
                        PrintUtil.print("清空缓冲区：字节数小于8，不符合数据");
                        return;
                    }


                }else if(funCode.equals("10")){

                    //重置读取位
                    in.resetReaderIndex();

                    //直接去前6个字节  78 作为crc
                    if(reablesLength>=8) {
                        byte[] mdatas = new byte[8];
                        in.readBytes(mdatas);
                        String data = bytes2HexString(mdatas);
                        byte[] data1 = {mdatas[0],mdatas[1],mdatas[2],mdatas[3],mdatas[4],mdatas[5]};
                        byte[] crcbyte = {mdatas[6],mdatas[7]};
                        String checkCrc2 = ModBusUtil.getCRC3(data1);

                        String crc = ModBusUtil.bytes2HexString(crcbyte);
                        if(crc.replace(" ","").equals(checkCrc2.replaceAll(" ",""))){
                            //添加数据
                            list.add(data);

                            //回收已读字节
                            in.discardReadBytes();

                            return;
                        }

                    }else {
                        in.clear();
                        PrintUtil.print("清空缓冲区：字节数小于8，不符合数据");
                        return;
                    }
                } else {
                    in.clear();
                    PrintUtil.print("清空缓冲区：字节数小于5，不符合数据");
                    return;

                }

            }else {
                in.clear();
               PrintUtil.print("清空缓冲区：字节数小于5，不符合数据");
                return;
            }

        } else {
            //最后不符合所有数据条件  断开连接
            in.clear();
            PrintUtil.print("清空数据 "+address+"不符合数据条件");
            return;
        }


    }



    //通用控制开关处理器







    /*
     * 字节数组转16进制字符串
     */
    public static String bytes2HexString(byte[] b) {
        String r = "";
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            r += hex.toUpperCase() + " ";
        }
        return r;
    }

    // 16进制字符串转换10进制
    public static int hex2decimal(String hex) {
        return Integer.parseInt(hex, 16);
    }

    //获取连接ctx的地址
    public String getRemoteAddress(ChannelHandlerContext ctx) {
        InetSocketAddress ipSocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = ipSocket.getAddress().getHostAddress();
        Integer port = ipSocket.getPort();
        String ip = clientIp + ":" + port;
        return ip;
    }


    //异常断开 和正常断开socket  清除连接
    public void disConnectDev(String address) {

        //modbus设备
        if (SocketMap.mRegPassDeviceMap != null && SocketMap.mRegPassDeviceMap.containsKey(address)) {
            ConMsg conMsg = SocketMap.mRegPassDeviceMap.get(address);
            conMsg.getCtx().close();
        }
        //json设备
        if (SocketMap.jRegPassDeviceMap != null && SocketMap.jRegPassDeviceMap.containsKey(address)) {
            ConMsg conMsg = SocketMap.jRegPassDeviceMap.get(address);
            conMsg.getCtx().close();
        }


        if (SocketMap.notRegDeviceMap != null && SocketMap.notRegDeviceMap.containsKey(address)) {
            ConMsg conMsg = SocketMap.notRegDeviceMap.get(address);
            conMsg.getCtx().close();
            SocketMap.notRegDeviceMap.remove(address);
        }
        if (SocketMap.regFailDeviceMap != null && SocketMap.regFailDeviceMap.containsKey(address)) {
            ConMsg conMsg = SocketMap.regFailDeviceMap.get(address);
            conMsg.getCtx().close();
            SocketMap.regFailDeviceMap.remove(address);
        }


    }

}


